//////////////////////////////////////////ok
#include"stdafx.h"

#include "bochs.h"

void IA32_CPU::INC_RX(Ia32_Instruction_c *i)
{
#if defined(IA32_HostAsm_Inc16)
  Bit32u flags32;
  asmInc16(gen_reg[i->opcodeReg()].word.rx, flags32);
  IA32_setEFlagsOSZAP(flags32);
#else
  Bit16u rx = ++ gen_reg[i->opcodeReg()].word.rx;
  IA32_SET_FLAGS_OSZAP_RESULT_16(rx, IA32_INSTR_INC16);
#endif
}

void IA32_CPU::DEC_RX(Ia32_Instruction_c *i)
{
#if defined(IA32_HostAsm_Dec16)
  Bit32u flags32;
  asmDec16(gen_reg[i->opcodeReg()].word.rx, flags32);
  IA32_setEFlagsOSZAP(flags32);
#else
  Bit16u rx = -- gen_reg[i->opcodeReg()].word.rx;
  IA32_SET_FLAGS_OSZAP_RESULT_16(rx, IA32_INSTR_DEC16);
#endif
}

void IA32_CPU::ADD_EwGw(Ia32_Instruction_c *i)
{
	Bit16u op2_16, op1_16, sum_16;
	op2_16 = IA32_READ_16BIT_REG(i->nnn());
	if (i->modC0()) 
	{
		op1_16 = IA32_READ_16BIT_REG(i->rm());
		sum_16 = op1_16 + op2_16;
		IA32_WRITE_16BIT_REG(i->rm(), sum_16);
	}
	else 
	{
		read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
		sum_16 = op1_16 + op2_16;
		write_RMW_virtual_word(sum_16);
	}
	IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
}

void IA32_CPU::ADD_GwEEw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, sum_16;
  unsigned nnn = i->nnn();
  op1_16 = IA32_READ_16BIT_REG(nnn);
  read_virtual_word(i->seg(), IA32_RMAddr(i), &op2_16);
#if defined(IA32_HostAsm_Add16)
  Bit32u flags32;
  asmAdd16(sum_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  sum_16 = op1_16 + op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
#endif
  IA32_WRITE_16BIT_REG(nnn, sum_16);
}

void IA32_CPU::ADD_GwEGw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, sum_16;
  unsigned nnn = i->nnn();
  op1_16 = IA32_READ_16BIT_REG(nnn);
  op2_16 = IA32_READ_16BIT_REG(i->rm());
#if defined(IA32_HostAsm_Add16)
  Bit32u flags32;
  asmAdd16(sum_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  sum_16 = op1_16 + op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
#endif
  IA32_WRITE_16BIT_REG(nnn, sum_16);
}

void IA32_CPU::ADD_AXIw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, sum_16;
  op1_16 = AX;
  op2_16 = i->Iw();
  sum_16 = op1_16 + op2_16;
  AX = sum_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
}

void IA32_CPU::ADC_EwGw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, sum_16;
  bx_bool temp_CF = getB_CF();
  op2_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    sum_16 = op1_16 + op2_16 + temp_CF;
    IA32_WRITE_16BIT_REG(i->rm(), sum_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    sum_16 = op1_16 + op2_16 + temp_CF;
    write_RMW_virtual_word(sum_16);
  }
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16,(temp_CF) ? IA32_INSTR_ADC16 : IA32_INSTR_ADD16);
}

void IA32_CPU::ADC_GwEw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, sum_16;
  bx_bool temp_CF = getB_CF();
  op1_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op2_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op2_16);
  }

  sum_16 = op1_16 + op2_16 + temp_CF;
  IA32_WRITE_16BIT_REG(i->nnn(), sum_16);
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16,(temp_CF) ? IA32_INSTR_ADC16 : IA32_INSTR_ADD16);
}

void IA32_CPU::ADC_AXIw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, sum_16;
  bx_bool temp_CF = getB_CF();
  op1_16 = AX;
  op2_16 = i->Iw();
  sum_16 = op1_16 + op2_16 + temp_CF;
  AX = sum_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16,(temp_CF) ? IA32_INSTR_ADC16 : IA32_INSTR_ADD16);
}

void IA32_CPU::SBB_EwGw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, diff_16;
  bx_bool temp_CF = getB_CF();
  op2_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    diff_16 = op1_16 - (op2_16 + temp_CF);
    IA32_WRITE_16BIT_REG(i->rm(), diff_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    diff_16 = op1_16 - (op2_16 + temp_CF);
    write_RMW_virtual_word(diff_16);
  }
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16,(temp_CF) ? IA32_INSTR_SBB16 : IA32_INSTR_SUB16);
}

void IA32_CPU::SBB_GwEw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;
  bx_bool temp_CF = getB_CF();
  op1_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op2_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op2_16);
  }
  diff_16 = op1_16 - (op2_16 + temp_CF);
  IA32_WRITE_16BIT_REG(i->nnn(), diff_16);
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16,(temp_CF) ? IA32_INSTR_SBB16 : IA32_INSTR_SUB16);
}

void IA32_CPU::SBB_AXIw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;
  bx_bool temp_CF = getB_CF();
  op1_16 = AX;
  op2_16 = i->Iw();
  diff_16 = op1_16 - (op2_16 + temp_CF);
  AX = diff_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16,(temp_CF) ? IA32_INSTR_SBB16 : IA32_INSTR_SUB16);
}

void IA32_CPU::SBB_EwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, diff_16;
  bx_bool temp_CF = getB_CF();
  op2_16 = i->Iw();
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    diff_16 = op1_16 - (op2_16 + temp_CF);
    IA32_WRITE_16BIT_REG(i->rm(), diff_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    diff_16 = op1_16 - (op2_16 + temp_CF);
    write_RMW_virtual_word(diff_16);
  }
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16,(temp_CF) ? IA32_INSTR_SBB16 : IA32_INSTR_SUB16);
}

void IA32_CPU::SUB_EwGw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, diff_16;
  op2_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
#if defined(IA32_HostAsm_Sub16)
    Bit32u flags32;
    asmSub16(diff_16, op1_16, op2_16, flags32);
    IA32_setEFlagsOSZAPC(flags32);
#else
    diff_16 = op1_16 - op2_16;
#endif
    IA32_WRITE_16BIT_REG(i->rm(), diff_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
#if defined(IA32_HostAsm_Sub16)
    Bit32u flags32;
    asmSub16(diff_16, op1_16, op2_16, flags32);
    IA32_setEFlagsOSZAPC(flags32);
#else
    diff_16 = op1_16 - op2_16;
#endif
    write_RMW_virtual_word(diff_16);
  }
#if !defined(IA32_HostAsm_Sub16)
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_SUB16);
#endif
}

void IA32_CPU::SUB_GwEw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;
  unsigned nnn = i->nnn();
  op1_16 = IA32_READ_16BIT_REG(nnn);
  if (i->modC0()) 
  {
    op2_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op2_16);
  }
#if defined(IA32_HostAsm_Sub16)
  Bit32u flags32;
  asmSub16(diff_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_SUB16);
#endif
  IA32_WRITE_16BIT_REG(nnn, diff_16);
}

void IA32_CPU::SUB_AXIw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16, diff_16;
  op1_16 = AX;
  op2_16 = i->Iw();
#if defined(IA32_HostAsm_Sub16)
  Bit32u flags32;
  asmSub16(diff_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_SUB16);
#endif
  AX = diff_16;
}

void IA32_CPU::CMP_EwGw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16;
  op2_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
  }
#if defined(IA32_HostAsm_Cmp16)
  Bit32u flags32;
  asmCmp16(op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  Bit16u diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
#endif
}

void IA32_CPU::CMP_GwEw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16;
  op1_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op2_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op2_16);
  }
#if defined(IA32_HostAsm_Cmp16)
  Bit32u flags32;
  asmCmp16(op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  Bit16u diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
#endif
}

void IA32_CPU::CMP_AXIw(Ia32_Instruction_c *i)
{
  Bit16u op1_16, op2_16;
  op1_16 = AX;
  op2_16 = i->Iw();
#if defined(IA32_HostAsm_Cmp16)
  Bit32u flags32;
  asmCmp16(op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  Bit16u diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
#endif
}

void IA32_CPU::CBW(Ia32_Instruction_c *i)
{
  AX = (Bit8s) AL;
}

void IA32_CPU::CWD(Ia32_Instruction_c *i)
{
  if (AX & 0x8000) 
  {
    DX = 0xFFFF;
  }
  else 
  {
    DX = 0x0000;
  }
}

void IA32_CPU::XADD_EwGw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, sum_16;
  /* XADD dst(r/m), src(r)
   * temp <-- src + dst         | sum = op2 + op1
   * src  <-- dst               | op2 = op1
   * dst  <-- tmp               | op1 = sum
   */
  op2_16 = IA32_READ_16BIT_REG(i->nnn());
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    sum_16 = op1_16 + op2_16;
    // and write destination into source
    // Note: if both op1 & op2 are registers, the last one written
    //       should be the sum, as op1 & op2 may be the same register.
    //       For example:  XADD AL, AL
    IA32_WRITE_16BIT_REG(i->nnn(), op1_16);
    IA32_WRITE_16BIT_REG(i->rm(), sum_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    sum_16 = op1_16 + op2_16;
    write_RMW_virtual_word(sum_16);
    /* and write destination into source */
    IA32_WRITE_16BIT_REG(i->nnn(), op1_16);
  }
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
}

void IA32_CPU::ADD_EEwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, sum_16;
  op2_16 = i->Iw();
  read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
#if defined(IA32_HostAsm_Add16)
  Bit32u flags32;
  asmAdd16(sum_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  sum_16 = op1_16 + op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
#endif
  write_RMW_virtual_word(sum_16);
}

void IA32_CPU::ADD_EGwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, sum_16;
  op2_16 = i->Iw();
  op1_16 = IA32_READ_16BIT_REG(i->rm());
#if defined(IA32_HostAsm_Add16)
  Bit32u flags32;
  asmAdd16(sum_16, op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  sum_16 = op1_16 + op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, IA32_INSTR_ADD16);
#endif
  IA32_WRITE_16BIT_REG(i->rm(), sum_16);
}

void IA32_CPU::ADC_EwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, sum_16;
  bx_bool temp_CF = getB_CF();
  op2_16 = i->Iw();
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    sum_16 = op1_16 + op2_16 + temp_CF;
    IA32_WRITE_16BIT_REG(i->rm(), sum_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    sum_16 = op1_16 + op2_16 + temp_CF;
    write_RMW_virtual_word(sum_16);
  }
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, (temp_CF) ? IA32_INSTR_ADC16 : IA32_INSTR_ADD16);
}

void IA32_CPU::SUB_EwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16, diff_16;
  op2_16 = i->Iw();
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
#if defined(IA32_HostAsm_Sub16)
    Bit32u flags32;
    asmSub16(diff_16, op1_16, op2_16, flags32);
    IA32_setEFlagsOSZAPC(flags32);
#else
    diff_16 = op1_16 - op2_16;
#endif
    IA32_WRITE_16BIT_REG(i->rm(), diff_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
#if defined(IA32_HostAsm_Sub16)
    Bit32u flags32;
    asmSub16(diff_16, op1_16, op2_16, flags32);
    IA32_setEFlagsOSZAPC(flags32);
#else
    diff_16 = op1_16 - op2_16;
#endif
    write_RMW_virtual_word(diff_16);
  }
#if !defined(IA32_HostAsm_Sub16)
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_SUB16);
#endif
}

void IA32_CPU::CMP_EwIw(Ia32_Instruction_c *i)
{
  Bit16u op2_16, op1_16;
  op2_16 = i->Iw();
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
  }
  else 
  {
    read_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
  }
#if defined(IA32_HostAsm_Cmp16)
  Bit32u flags32;
  asmCmp16(op1_16, op2_16, flags32);
  IA32_setEFlagsOSZAPC(flags32);
#else
  Bit16u diff_16 = op1_16 - op2_16;
  IA32_SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, IA32_INSTR_COMPARE16);
#endif
}

void IA32_CPU::NEG_Ew(Ia32_Instruction_c *i)
{
  Bit16u op1_16, diff_16;
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    diff_16 = -op1_16;
    IA32_WRITE_16BIT_REG(i->rm(), diff_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    diff_16 = -op1_16;
    write_RMW_virtual_word(diff_16);
  }
  IA32_SET_FLAGS_OSZAPC_RESULT_16(diff_16, IA32_INSTR_NEG16);
}

void IA32_CPU::INC_Ew(Ia32_Instruction_c *i)
{
  Bit16u op1_16;
  if (i->modC0()) 
  {
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    op1_16++;
    IA32_WRITE_16BIT_REG(i->rm(), op1_16);
  }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
    op1_16++;
    write_RMW_virtual_word(op1_16);
  }
  IA32_SET_FLAGS_OSZAP_RESULT_16(op1_16, IA32_INSTR_INC16);
}

void IA32_CPU::DEC_Ew(Ia32_Instruction_c *i)
{
  Bit16u op1_16;
  if (i->modC0()) 
  {
#if defined(IA32_HostAsm_Dec16)
    Bit32u flags32;
    asmDec16(gen_reg[i->rm()].word.rx, flags32);
    IA32_setEFlagsOSZAP(flags32);
#else
    op1_16 = IA32_READ_16BIT_REG(i->rm());
    op1_16--;
    IA32_WRITE_16BIT_REG(i->rm(), op1_16);
#endif
    }
  else 
  {
    read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
#if defined(IA32_HostAsm_Dec16)
    Bit32u flags32;
    asmDec16(op1_16, flags32);
    IA32_setEFlagsOSZAP(flags32);
#else
    op1_16--;
#endif
    write_RMW_virtual_word(op1_16);
  }
#if !defined(IA32_HostAsm_Dec16)
  IA32_SET_FLAGS_OSZAP_RESULT_16(op1_16, IA32_INSTR_DEC16);
#endif
}

void IA32_CPU::CMPXCHG_EwGw(Ia32_Instruction_c *i)
{
	Bit16u op2_16, op1_16, diff_16;
	if (i->modC0()) 
	{
		op1_16 = IA32_READ_16BIT_REG(i->rm());
	}
	else 
	{
		read_RMW_virtual_word(i->seg(), IA32_RMAddr(i), &op1_16);
	}
	diff_16 = AX - op1_16;
	IA32_SET_FLAGS_OSZAPC_16(AX, op1_16, diff_16, IA32_INSTR_COMPARE16);
	if (diff_16 == 0) 
	{  // if accumulator == dest
		// dest <-- src
		op2_16 = IA32_READ_16BIT_REG(i->nnn());
		if (i->modC0()) 
		{
			IA32_WRITE_16BIT_REG(i->rm(), op2_16);
		}
		else 
		{
			write_RMW_virtual_word(op2_16);
		}
	}
	else 
	{
		// accumulator <-- dest
		AX = op1_16;
	}
}
